import requests
import time
import json
import os
import logging
from pathlib import Path
from dotenv import load_dotenv
from jinja2 import Environment, FileSystemLoader

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# 加载环境变量
load_dotenv()

# 新增模板渲染模块
class TemplateRenderer:
    def __init__(self,template_dir="templates"):
        # 设置模板目录
        self.env = Environment(
            loader=FileSystemLoader(template_dir),
            autoescape=True,
            trim_blocks=True,
            lstrip_blocks=True
        )
        
    def render_news(self, data: dict) -> str:
        """渲染新闻模板"""
        template = self.env.get_template("template_2.html")
        return template.render(**data)

class WeChatOfficialAccount:
    def __init__(self,template_dir="templates"):
        self.appid = os.getenv("APP_ID")
        self.appsecret = os.getenv("APP_SECRET")
        self.access_token = None
        self.token_expires = 0  # 过期时间戳
        self.renderer = TemplateRenderer(template_dir)

    def generate_news_html(self, data: dict) -> str:
        """使用Jinja2生成HTML内容"""
        # 简化数据处理逻辑
        news = [item.split('、', 1)[1] for item in data["news"]]
        logging.info("处理数据{}".format(data))
        return self.renderer.render_news({
            "news": news,
            "weiyu": data["weiyu"],
            "date": data["date"],
            "head_image": data["head_image"]
        })

    def get_access_token(self, force_refresh=False):
        """获取微信access_token，带缓存机制"""
        # 如果token未过期且不需要强制刷新，则返回现有token
        if not force_refresh and self.access_token and time.time() < self.token_expires:
            logging.info("使用缓存的 access_token")
            return self.access_token
            
        url = "https://api.weixin.qq.com/cgi-bin/token"
        params = {
            "grant_type": "client_credential",
            "appid": self.appid,
            "secret": self.appsecret
        }
        
        try:
            response = requests.get(url, params=params)
            response.raise_for_status()
            data = response.json()
            
            if "access_token" in data:
                self.access_token = data["access_token"]
                # 提前5分钟过期，防止边界情况
                self.token_expires = time.time() + data["expires_in"] - 300
                logging.info("成功获取新的 access_token")
                return self.access_token
            else:
                logging.error(f"获取access_token失败: {data}")
                raise Exception(f"获取access_token失败: {data}")
        except Exception as e:
            logging.error(f"获取access_token异常: {str(e)}")
            raise Exception(f"获取access_token异常: {str(e)}")

    def upload_image(self, image_path, is_online=False):
        """上传永久图片素材，返回media_id和url"""
        url = "https://api.weixin.qq.com/cgi-bin/material/add_material"
        params = {
            "access_token": self.get_access_token(),
            "type": "image"
        }
        
        try:
            if is_online:
                # 处理在线图片
                response = requests.get(image_path)
                response.raise_for_status()
                files = {"media": (Path(image_path).name, response.content)}
            else:
                # 处理本地图片
                with open(image_path, "rb") as f:
                    files = {"media": (Path(image_path).name, f)}
        
            response = requests.post(url, params=params, files=files)
            response.raise_for_status()
            data = response.json()
            
            if "media_id" in data:
                logging.info(f"图片上传成功，media_id: {data['media_id']}")
                return {
                    "media_id": data["media_id"],
                    "url": data.get("url", "")
                }
            else:
                logging.error(f"上传图片失败: {data}")
                raise Exception(f"上传图片失败: {data}")
        except Exception as e:
            logging.error(f"上传图片异常: {str(e)}")
            raise Exception(f"上传图片异常: {str(e)}")

    def create_draft(self, articles):
        """创建图文草稿"""
        url = "https://api.weixin.qq.com/cgi-bin/draft/add"
        params = {
            "access_token": self.get_access_token()
        }
        
        payload = {
            "articles": articles
        }
        
        try:
            response = requests.post(
                url,
                params=params,
                data=json.dumps(payload, ensure_ascii=False).encode("utf-8")
            )
            response.raise_for_status()
            data = response.json()
            
            if data.get("errcode", 0) == 0:
                logging.info(f"草稿创建成功，media_id: {data['media_id']}")
                return data["media_id"]
            else:
                logging.error(f"创建草稿失败: {data}")
                raise Exception(f"创建草稿失败: {data}")
        except Exception as e:
            logging.error(f"创建草稿异常: {str(e)}")
            raise Exception(f"创建草稿异常: {str(e)}")

    def public_article(self, media_id):
        """发布草稿为正式文章"""
        
        url = "https://api.weixin.qq.com/cgi-bin/freepublish/submit?access_token={}".format(self.get_access_token())
        payload = {
            "media_id": media_id
        }
        
        try:
            response = requests.post(
                url,
                data=json.dumps(payload, ensure_ascii=False).encode("utf-8")
            )
            response.raise_for_status()
            data = response.json()
            logging.info(f"文章发布成功，media_id: {media_id}")
        except requests.exceptions.RequestException as e:
            logging.error(f"发布草稿异常: {str(e)}")
            raise Exception(f"发布草稿异常: {str(e)}")



